home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Publishing / ImagePortfolio / Source / objectThreadPerform.h < prev    next >
Text File  |  1994-04-01  |  7KB  |  119 lines

  1. // -------------------------------------------------------------------------------------
  2. // objectThreadPerform.m
  3. // Martin D. Flynn, NeXT Computer, Inc.
  4. //
  5. // This category of Object provides a general solution for thread support which includes
  6. // a solution for allowing threads to communicate with the window/event manager.
  7. //
  8. // Using 'forkPerform:detach:', a thread can be created to perform some action in the
  9. // background while the window manager (main thread) is free to handle events.
  10. //
  11. // In addition to creating new threads, support is provided to allow a forked thread to
  12. // communicate with the main thread to tell it to execute actions, such as drawing in a
  13. // view, and even returning values.  This is accomplished through calls to
  14. // 'mainThreadPerform:with:wait:'.  This method can be called from any thread, making sure
  15. // that the main thread is the only thread that will process the specified action.  These
  16. // methods are object independent, meaning that 'mainThreadPerform:wait:' can be sent to
  17. // ANY object from ANY thread.  For instance, a forked thread could set the title of some
  18. // button with the following:
  19. //   [someButtonId mainThreadPerform:@selector(setTitleNoCopy:) with:aStaticTitle wait:NO];
  20. // (A forked thread should not try to set the title of a button itself, or execute any
  21. // other method that causes drawing to occur.  This is because it has no way of knowing
  22. // what drawing may already be occurring, and it may in fact cause drawing to occur in a
  23. // view other than where it was originally intended.)
  24. //
  25. // The return value can also be obtained from the method executed from the main thread by
  26. // setting 'wait:YES'.  For example, to wait for a return value from a method executed
  27. // from the main thread you could issue the following message:
  28. //   rtn = [myObject mainThreadPerform:@selector(showErrorPanel:) with:errorMsg wait:YES];
  29. // The value that 'showErrorPanel:' returned in the main thread would be returned to the
  30. // calling thread.  This is helpful when a thread wishes to display an error panel, then
  31. // act on the response from the user.
  32. //
  33. // -------------------------------------------------------------------------------------
  34. #import <mach/cthreads.h>
  35. #import <objc/Object.h>
  36.  
  37. // -------------------------------------------------------------------------------------
  38. // thread perform macros (Object category enhancements)
  39. // (see 'mainThreadPerform:wait:' below for more informaiton)
  40. #define    isMainTHREAD            [Object isMainThread]
  41. #define    _cmdPERFORM(P)            [self mainThreadPerform:_cmd with:(id)(P) wait:NO]
  42. #define _cmdPERFORMw(P)            [self mainThreadPerform:_cmd with:(id)(P) wait:YES]
  43. #define    _cmdINVOKE(P)            { if (!isMainTHREAD) return _cmdPERFORM(P); }
  44. #define    _cmdINVOKEw(P)            { if (!isMainTHREAD) return _cmdPERFORMw(P); }
  45.  
  46. // -------------------------------------------------------------------------------------
  47. @interface Object(ThreadPerform)
  48. // -------------------------------------------------------------------------------------
  49. + initThreadSupport;
  50. //  This initialization will occur automatically when 'forkPerform:...' is executed from
  51. //  the main thread.  You may call this method to explicitly initialize this thread
  52. //  support prior to calling 'forkPerform:...'
  53. //
  54. // -------------------------------------------------------------------------------------
  55. + (BOOL)isMainThread;
  56. - (BOOL)isMainThread;
  57. //  These methods return true if called from the main thread, else they return false.
  58. //  Valid only after a call to 'initThreadSupport', or 'forkPerform:...', has been made.
  59. //
  60. // -------------------------------------------------------------------------------------
  61. - perform:(SEL)selector with:arg1 with:arg2 argCount:(int)argCount;
  62. //  This method is a shell for the individual 'perform:[with:[with:]]' with the specified
  63. //  number of arguments.
  64. //  An argCount of 0 would send [self perform:selector];
  65. //  An argCount of 1 would send [self perform:selector with:arg1]; 
  66. //  An argCount of 2 would send [self perform:selector with:arg1 with:arg2];
  67. //  Any other value for argCount will be ignored.
  68. //
  69. // -------------------------------------------------------------------------------------
  70. - mainThreadPerform:(SEL)aSelector wait:(BOOL)waitFlag;
  71. - mainThreadPerform:(SEL)aSelector with:anArg wait:(BOOL)waitFlag;
  72. - mainThreadPerform:(SEL)aSelector with:anArg0 with:anArg1 wait:(BOOL)waitFlag;
  73. //  This method will cause aSelector to be executed by the main thread.     If the calling
  74. //  thread is not the main thread, this method sends an aSelector message through a Mach
  75. //  port to the main thread to be executed.  If the calling thread is the main thread,
  76. //  then the aSelector message is sent directly.  If waitFlag is true, then the calling
  77. //  thread will be suspended until the main thread completes the execution of the message,
  78. //  and the return value will be that of the aSelector message executed from the main
  79. //  thread.  If waitFlag is false, then this method returns (id)nil.
  80. //    Macros:    _cmdPERFORM(anArg)        /* [self mainThreadPerform:_cmd with:anArg wait:NO]   */
  81. //             _cmdPERFORMw(anArg)        /* [self mainThreadPerform:_cmd with:anArg wait:YES]  */
  82. //             _cmdINVOKE(anArg)        /* { if (!isMainTHREAD) return _cmdPERFORM(anArg); }  */
  83. //             _cmdINVOKEw(anArg)        /* { if (!isMainTHREAD) return _cmdPERFORMw(anArg); } */
  84. //
  85. //  Note on use of _cmdINVOKE(anArg) and _cmdINVOKEw(anArg) :
  86. //    To guarentee that a method is executed from the main thread the method need only 
  87. //    include '_cmdINVOKE(anArg);' at the beginning of the method.  When this macro is
  88. //    executed, it checks to see if it is the main thread.  If it is not then it is sent
  89. //    to the main thread and the macro causes the method to return.  If it is executed
  90. //    from the main thread, as it would be after being sent to _cmdPERFORM(anArg), then
  91. //    the method is allowed to execute normally.  Using _cmdINVOKEw(anArg) performs
  92. //    the same as _cmdINVOKE(anArg) except that it waits for the main thread to finish
  93. //    execution of the method before returning.  It is important to note that if this
  94. //    method is implemented in a subclass, it is important that the subclass implementation
  95. //    duplicate the the call to the macro at the beginning of the method.  Otherwise
  96. //    unpredictable results may occur.
  97. //
  98. //  Example use of _cmdINVOKE(anArg);
  99. //        - setButtonState:(BOOL)newState
  100. //        {
  101. //            _cmdINVOKE(newState);
  102. //            [myButton setState:newState];
  103. //            // ... other code here ...
  104. //            return self;
  105. //        }
  106. // 
  107. // -------------------------------------------------------------------------------------
  108. - (cthread_t)forkPerform:(SEL)aSelector detach:(BOOL)detach;
  109. - (cthread_t)forkPerform:(SEL)aSelector with:anArg detach:(BOOL)detach;
  110. - (cthread_t)forkPerform:(SEL)aSelector with:anArg0 with:anArg1 detach:(BOOL)detach;
  111. //    This method creates a new thread in which the aSelector message is executed.  The
  112. //    cthread handle for the created thread is returned if 'detach:NO' was specified, and
  113. //  normal cthread functions may be performed on this handle.  Nil is returned if
  114. //  'detach:YES' was specified, since there is no guarantee that the returned value would
  115. //  ever be valid (ie. The thread could terminate before you use the handle).
  116. //     
  117. // -------------------------------------------------------------------------------------
  118. @end
  119.